`include "chunjun_define.sv" 
`include "chunjun_lib_define.sv" 

//==============================================================
// Date        : 28 Nov 2024
// Description : PLRU for the whole cache array
//  
//==============================================================

module wing_cbb_plru_array #(
    parameter PORT_N  = 1,    // DO NOT Change !!!
    parameter WAY_N   = 4,    // DO NOT Change !!!
    parameter SET_N   = 512,
    // Do not modify the following parameter
    parameter INDEX_W = $clog2(SET_N) 
) (
    input  logic                           clk,
    input  logic                           rst_n,
    input  logic                           valid,
    input  logic [PORT_N-1:0]              hit_miss,   // 1'b1-hit  1'b0:miss
    input  logic [PORT_N-1:0][INDEX_W-1:0] index,
    input  logic [PORT_N-1:0][WAY_N-1:0]   hit_way,    // bitmap
    input  logic [PORT_N-1:0][WAY_N-1:0]   lock_way,   // bitmap
    output logic [PORT_N-1:0][WAY_N-1:0]   rplc_way_o  // bitmap
);

logic all_way_lock;
 
logic [SET_N-1:0]            dff_plru_code_en;
logic [SET_N-1:0][WAY_N-2:0] dff_plru_code_d;
logic [SET_N-1:0][WAY_N-2:0] dff_plru_code_q;
logic [SET_N-1:0][WAY_N-2:0] plru_code_array;

logic [PORT_N-1:0][WAY_N-2:0] code_initial;
logic [WAY_N-2:0] code_out_hit;
logic [WAY_N-2:0] code_out_miss;
logic [WAY_N-2:0] code_out;

logic [PORT_N-1:0][WAY_N-1:0] rplc_way_tmp;
 
// --------------- Indicator Signals ------------------
assign all_way_lock = & lock_way;
assign code_initial = plru_code_array[index];


// ----------------- Code Array ------------------
for (genvar i=0; i<SET_N; i++) begin: code_array
 
    assign dff_plru_code_en[i] = (i == index) & valid & ~all_way_lock;
    assign dff_plru_code_d[i]  = code_out;

    `WDFFER(dff_plru_code_q[i], dff_plru_code_d[i], dff_plru_code_en[i], clk, rst_n)
 
end
 
assign plru_code_array = dff_plru_code_q;


// --------------------- 1 PORT ----------------------
if (PORT_N == 1) begin: port_1
    // encode
    wing_cbb_plru_encode #( .WAY_N(WAY_N)    )
        u_encode_hit ( .way_info_i( hit_way      ),
                       .code_i    ( code_initial ),
                       .code_o    ( code_out_hit )
        );

    wing_cbb_plru_encode #( .WAY_N(WAY_N)    )
        u_encode_miss ( .way_info_i( rplc_way_o[0] ),
                        .code_i    ( code_initial  ),
                        .code_o    ( code_out_miss )
        );
 
    assign code_out = hit_miss ? code_out_hit : code_out_miss;

    // decode
    wing_cbb_plru_decode #( .WAY_N(WAY_N)       )
        u_decode ( .lock_way_i( lock_way        ),
                   .code_i    ( code_initial    ),
                   .rplc_way_o( rplc_way_tmp[0] )
        );
 
    assign rplc_way_o[0] = all_way_lock ? {WAY_N{1'b0}} : rplc_way_tmp[0];
 
end
 
 
endmodule

`include "chunjun_undefine.sv" 
